#include "WoodenTextureShader.h"
#include <glad/glad.h>
#include <iostream>
#include "Renderer.h"
#include "ShaderProgram.h"

using namespace std;
WoodenTextureShader::WoodenTextureShader()
{
    vertices = {
        // positions                    // colors                     // texture
        // coords
        0.5f,  0.5f,  0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
        0.5f,  -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
        -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
        -0.5f, 0.5f,  0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f  // top left
    };

    vertexShaderSource = "#version 330 core                     \n\
                    layout(location=0) in vec3 aPos;            \n\
                    layout(location=1) in vec3 color;           \n\
                    layout(location=2) in vec2 textureCoord;    \n\
                    out vec3 ourColor;                          \n\
                    out vec2 texCoord;                          \n\
                    void main(){                                \n\
                        gl_Position = vec4(aPos,1.0);           \n\
                        ourColor =   color;                     \n\
                        texCoord = textureCoord;                \n\
    }\0";

    /**
    The fragment shader should then accept the TexCoord output variable as an
    input variable.

    The fragment shader should also have access to the texture object, but how
    do we pass the texture object to the fragment shader? GLSL has a built-in
    data-type for texture objects called a sampler that takes as a postfix the
    texture type we want e.g. sampler1D, sampler3D or in our case sampler2D. We
    can then add a texture to the fragment shader by simply declaring a uniform
    sampler2D that we later assign our texture to
    片段着色器不仅要接收纹理坐标，同时还要接受纹理对象
    在GLSL语言中，纹理对象用 sampler2D 表示
     */
    fragmentShaderSource = "#version 330 core                   \n\
                            in vec3 ourColor;                   \n\
                            in vec2 texCoord;                   \n\
                            uniform sampler2D texture1;       \n\
                            uniform sampler2D texture2;    \n\
                            out vec4 FragColor;                 \n\
                            void main(){                        \n\
                                 FragColor = mix( texture( texture1,texCoord), texture(texture2,texCoord) ,0.2) ;\n\
    }\0";
    //                              FragColor =  texture(textureObj,texCoord) *
    //                              vec4(ourColor,1.0); \n
    //
    //
    indices = {0, 2, 3, 0, 1, 2};
}

unsigned int WoodenTextureShader::createShaderProgram()
{
    auto shader = ShaderProgram::createShaderProgram();

    textureObjLocation = glGetUniformLocation(shader, "texture1");

    if (textureObjLocation == -1)
    {
        cout << "failed to get textureObj's Location" << endl;
    }

    secondTextureLocation = glGetUniformLocation(shader, "texture2");
    if (secondTextureLocation == -1)
    {
        cout << "failed to get secondTexture's Location" << endl;
    }
    return shader;
}

void WoodenTextureShader::prepareVAO()
{

    unsigned int VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float),
                 vertices.data(), GL_STATIC_DRAW);

    // 传送矩形的4个顶点
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float),
                          (void*)0);

    // 传送color
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float),
                          (void*)(3 * sizeof(float)));

    // 传送纹理坐标
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float),
                          (void*)(6 * sizeof(float)));

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);

    // 1、创建EBO对象
    unsigned int EBO;
    glGenBuffers(1, &EBO);

    // 2、绑定EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

    // 3、拷贝顶点顺序索引到EBO中
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(int),
                 this->indices.data(), GL_STATIC_DRAW);

    texture1 = Renderer::loadTexture("./resources/wooden_container_texture.jpg",
                                     GL_TEXTURE0, GL_RGB);

    texture2 = Renderer::loadTexture(
        "./resources/awesomeface.png", GL_TEXTURE1,
        /**
        Note that we now load a .png image that includes an alpha (transparency)
        channel. This means we now need to specify that the image data contains
        an alpha channel as well by using GL_RGBA; otherwise OpenGL will
        incorrectly interpret the image data.
        */
        GL_RGBA);

    glUseProgram(shaderProgram);

    /**
    * 显式告诉着色器使用哪个纹理单元，确保跨平台/驱动的可靠性。
    location of a texture 被叫做 texture unit
    texture unit 可以取以下的值
    GL_TEXTURE0、GL_TEXTURE1、GL_TEXTURE2 ... GL_TEXTURE15
    使用 glUniform1i 可以把 texture unit 绑定到 Fragment Shader 的 uniform
    sampler2D 上 其中 一个 Fragment Shader 中可以有多个 uniform sampler2D
    */
    glUniform1i(textureObjLocation, 1);
    glUniform1i(secondTextureLocation, 0);
}

void WoodenTextureShader::update() {}

void WoodenTextureShader::render()
{

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
